home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / terms / kermit / b / ckitio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-06  |  36.8 KB  |  1,567 lines

  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2. /* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
  3. /* |. o.| || This program may not be distributed without the permission of   */
  4. /* | .  | || the authors.                                                    */
  5. /* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
  6. /* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
  7. /* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */
  8. /*                                                                           */
  9. /* Contributed to Columbia University for inclusion in C-Kermit.             */
  10. /* Permission is granted to any individual or institution to use, copy, or   */
  11. /* redistribute this software so long as it is not sold for profit, provided */
  12. /* this copyright notice is retained.                                        */
  13. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  14.  
  15. char *ckxv = "Amiga tty I/O $Id: ckitio.c,v 1.9 93/08/03 08:36:07 swalton Exp Locker: swalton $";
  16.  
  17. /*  C K I T I O  --  Serial and Console I/O support for the Amiga */
  18.  
  19. /*
  20.  * Author: Jack Rouse, The Software Distillery
  21.  * Based on the CKUTIO.C module for Unix
  22.  *
  23.  * Modified for Manx Aztec C and Version 1.2 and forward of Amiga's OS by
  24.  * Stephen Walton of California State University, Northridge,
  25.  * srw@csun.edu.  Further mods documented in ckiker.upd.
  26.  *
  27.  
  28.  $Log:    ckitio.c,v $
  29.  * Revision 1.9  93/08/03  08:36:07  swalton
  30.  * Many changes thanks to Olaf Barthel:
  31.  * 1.  Changed include files to Amiga standard.
  32.  * 2.  Changed signal-handling to use ANSI signal() call.  Still can't
  33.  *     call Aztec Chk_Abort(), though, because it ignores signal().
  34.  * 3.  Used GetScreenData() on the Workbench screen to find the window
  35.  *     size to open.
  36.  * 4.  Deleted DoIOQuick() and changed calls to it to DoIO(), which is
  37.  *     identical.
  38.  * 5.. ttol() rewritten to have a static buffer whose size is checked
  39.  *     and to handle the pendwrite flag correctly.
  40.  * 
  41.  * Revision 1.8  92/10/30  16:14:46  swalton
  42.  * Put in code to attempt to open a 1024 by 1024 console, at John Ata's
  43.  * suggestion.  This will make a maximum-size window on most Amigas.
  44.  * 
  45.  * Added code to set a global int "v37" to TRUE or FALSE according to the
  46.  * version of the ROM Kernel.  This is then used in other places to
  47.  * conditionally turn on V37 features.
  48.  * 
  49.  * Revision 1.7  92/03/16  13:50:58  swalton
  50.  * Support added for CTR/RTS flow control, using the new FLO_ manifest
  51.  * constants in version 5A.
  52.  *
  53.  * Revision 1.6  92/01/15  17:12:35  swalton
  54.  * Added Long BREAK support with new ttsndlb() routine.
  55.  *
  56.  * Added support for multiple devices;  the SET LINE command now takes a
  57.  * line of the form "device/unit".
  58.  *
  59.  *  Revision 1.5  91/07/18  16:04:57  swalton
  60.  *  ttinl() now null terminates a received packet correctly.
  61.  *
  62.  *  Revision 1.4  91/05/29  09:08:57  swalton
  63.  *  1.  Changed function definitions to prototype style.  Required adding
  64.  *      a few forward declarations.
  65.  *  2.  Removed includes of stdio.h, stdlib.h, and string.h, as they are
  66.  *      now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS.
  67.  *
  68.  *  Revision 1.3  90/11/19  21:46:54  swalton
  69.  *  Modifications for compiling with SAS/C Version 5.10, courtesy of
  70.  *  Larry Rosenman (ler@erami.lonestar.org, ler on BIX)
  71.  *
  72.  *  Revision 1.2  90/11/07  14:42:07  swalton
  73.  *  Version 1.2--released to world as first beta test version simultaneously
  74.  *  with release of edit 5A(160).
  75.  *
  76.  *  Revision 1.1  90/07/12  22:30:11  swalton
  77.  *  Rather extensive changes were made to ckitio.c, mainly to add new functions
  78.  * required for the proper operation of C Kermit 5A(149).  They are not listed
  79.  * in detail here;  refer to the parts of the C Kermit interface document
  80.  * (file ckasys.doc in the Kermit archive) for the portions labeled *NEW*.
  81.  * These will point you at the code revisions.
  82.  *
  83.  * Revision 1.0  90/04/30  11:54:27  swalton
  84.  * Initial revision
  85.  *
  86.  */
  87.  
  88. #include "ckcdeb.h"
  89. #include "ckcker.h"
  90. #include "ckcnet.h"
  91. #include <exec/types.h>
  92. #include <exec/exec.h>
  93. #include <devices/serial.h>
  94. #include <devices/timer.h>
  95. #include <libraries/dos.h>
  96. #include <libraries/dosextens.h>
  97. #define fh_Interact fh_Port
  98. #define fh_Process fh_Type
  99. #include <intuition/intuition.h>
  100. #include <intuition/intuitionbase.h>
  101. #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)
  102. #include <string.h>
  103. #ifdef AZTEC_C
  104. #include <fcntl.h>
  105. #include <signal.h>
  106. char *ckxsys = " Commodore Amiga (Aztec_C)";    /* system name */
  107. #else
  108. #ifdef __SASC
  109. #include <fcntl.h>
  110. #include <signal.h>
  111. #include <ios1.h>        /* defines ufbs structure */
  112. char *ckxsys = " Commodore Amiga (SAS/C)";    /* system name */
  113. #endif
  114. #endif
  115.  
  116. #include <clib/exec_protos.h>
  117. #include <clib/alib_protos.h>
  118. #include <clib/dos_protos.h>
  119. #include <clib/intuition_protos.h>
  120.  
  121. /* external definitions */
  122. char *dftty = SERIALNAME;        /* serial device name */
  123. int dfloc = 1;                /* serial line is external */
  124. int dfprty = 0;                /* default parity is none */
  125. int ttprty = 0;                /* parity in use */
  126. int dfflow = FLO_XONX;            /* default flow control is on */
  127. int backgrd = 0;            /* default to foreground */
  128. int ckxech = 0;                /* echo in case redirected stdin */
  129. int tvtflg = 0;                /* Flag for ttvt() called. */
  130. int ttcarr = 0;                /* Carrier detection mode */
  131. int ttnproto = NP_NONE;            /* Protocol for network device */
  132.  
  133. struct Process *CurProc;        /* current process */
  134. struct CommandLineInterface *CurCLI;    /* current CLI info */
  135. struct IntuitionBase *IntuitionBase;    /* ptr to Intuition lib */
  136. short v37;                /* Are we version 37? */
  137.  
  138. /* static definitions */
  139. static struct MsgPort *serport;        /* message port for serial comm */
  140. static struct MsgPort *conport;        /* console packet port */
  141. static struct timerequest *TimerIOB;    /* timer request */
  142. static struct IOExtSer *ReadIOB;    /* serial input request */
  143. static struct IOExtSer *WriteIOB;    /* serial output request */
  144. static struct DosPacket *conpkt;    /* console I/O packet */
  145. static WORD serialopen;            /* true iff serial device open */
  146. static WORD timeropen;            /* true iff timer device open */
  147. static WORD pendwrite;            /* true iff WriteIOB in use */
  148. static WORD pendread;            /* true iff ReadIOB in use */
  149. static WORD pendconsole;        /* true when console read pending */
  150. static int queuedser;            /* serial pushback char or -1 */
  151. static UBYTE serbufc;            /* char buffer for read ahead I/O */
  152. #define NTTOQ 64            /* connect output queue size */
  153. static char ttoq[NTTOQ];        /* connect output queue */
  154. static int nttoq;            /* number of chars in ttoq */
  155. static int pttoq;            /* next char to output in ttoq */
  156. static int queuedcon;            /* contti pushback char or -1 */
  157. static LONG intsigs;            /* signals for aborting serial I/O */
  158. static BPTR rawcon;            /* file handle for RAW: window */
  159. static BPTR saverr;                     /* saved stderr file handle */
  160. static APTR savewindow;            /* saved process WindowPtr */
  161. static APTR pushwindow;            /* pushed process WindowPtr */
  162. static struct DateStamp prevtime;    /* saved time value */
  163.  
  164.  
  165. /* AmigaDOS support (from ckiutl.c) */
  166. struct DosPacket *CreatePacket(void);
  167. VOID DeletePacket(struct DosPacket *);
  168.  
  169. #ifdef AZTEC_C
  170. /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */
  171. #define DOSFH(n) (_devtab[n].fd)
  172. /* translate Unix file handle (0, 1, or 2) to Aztec file handle */
  173. #define FILENO(n) (n)
  174. extern int Enable_Abort;
  175. #else
  176. /* Lattice runtime externals */
  177. #ifdef __SASC
  178. #define DOSFH(n) (chkufb(n)->ufbfh)
  179. #define FILENO(n) (n)
  180. #endif
  181. #endif
  182.  
  183. /*
  184.  * Under ANSI C, pointer-pointer assignments are illegal without an
  185.  * explicit cast.  So, we define the following to make such casts short.
  186.  */
  187. #define IOR struct IORequest
  188.  
  189. /*
  190.  * Forward declarations
  191.  */
  192. void reqres(void);
  193. static void testint(long);
  194. #ifdef AZTEC_C
  195. #define Chk_Abort() testint(0L)
  196. #else
  197. void Chk_Abort(void);        /* or #define Chk_Abort() testint(0) */
  198. #endif
  199.  
  200. /*
  201.  * make note of a serial error and quit
  202.  */
  203. static void
  204. Fail(char *msg)
  205. {
  206.     syscleanup();
  207.     fprintf(stderr, msg);
  208.     fprintf(stderr, "\n");
  209.     exit(2);
  210. }
  211.  
  212. void
  213. emergency(void) {
  214.     (void) syscleanup();
  215. }
  216.  
  217. /*
  218.  *  sysinit -- Amiga specific initialization
  219.  */
  220. int
  221. sysinit(void)
  222. {
  223.     struct IOExtSer *iob;
  224.  
  225.     /* set current process info */
  226.     CurProc = (struct Process *)FindTask((char *)NULL);
  227.     CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI);
  228.     backgrd = (CurCLI == NULL || CurCLI->cli_Background);
  229.     savewindow = CurProc->pr_WindowPtr;
  230.  
  231.     signal(SIGINT, SIG_IGN);
  232.  
  233.     /* allocate console ports and IO blocks */
  234.     if ((conport = CreatePort((char *)NULL, 0L)) == NULL)
  235.         Fail("no console MsgPort");
  236.     if ((conpkt = CreatePacket()) == NULL)
  237.         Fail("no console packet");
  238.  
  239.     /* allocate serial ports and IO blocks */
  240.     if ((serport = CreatePort((char *)NULL, 0L)) == NULL)
  241.         Fail("no serial MsgPort");
  242.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  243.     if ((WriteIOB = iob) == NULL) Fail("no WriteIOB");
  244.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  245.     if ((ReadIOB = iob) == NULL) Fail("no ReadIOB");
  246.  
  247.     /* open the timer device */
  248.     TimerIOB = (struct timerequest *)
  249.            CreateExtIO(serport,(LONG)sizeof(*TimerIOB));
  250.     if (TimerIOB == NULL) Fail("no TimerIOB");
  251.     if (OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, (IOR *)TimerIOB, 0L) != 0)
  252.         Fail("no timer device");
  253.     timeropen = TRUE;
  254.  
  255.     /* open the Intuition library */
  256.     if (!IntuitionBase &&
  257.         (IntuitionBase = (struct IntuitionBase *)
  258.                  OpenLibrary("intuition.library", 0L) ) == NULL )
  259.         Fail("can't open Intuition");
  260.  
  261.     if (((struct Library *)IntuitionBase)->lib_Version >= 37)
  262.         v37 = TRUE;
  263.     else
  264.         v37 = FALSE;
  265.     /* open the serial device to get configuration */
  266.     iob->io_SerFlags = SERF_SHARED;
  267.     if (OpenDevice(SERIALNAME, 0L, (IOR *)iob, 0L) != 0)
  268.         Fail("can't open serial.device");
  269.     /* set parameters from system defaults */
  270.     if (!(iob->io_SerFlags & SERF_XDISABLED))
  271.         dfflow = FLO_XONX;
  272.     else if (iob->io_SerFlags & SERF_7WIRE)
  273.         dfflow = FLO_RTSC;
  274.     else
  275.         dfflow = FLO_NONE;
  276.     /*
  277.      * Set default (startup) parity from Preferences settings.
  278.       */
  279.     if (iob->io_SerFlags & SERF_PARTY_ON)     /* Parity is on */
  280.         if (iob->io_ExtFlags & SEXTF_MSPON)    /* Space or mark */
  281.             if (iob->io_ExtFlags & SEXTF_MARK)
  282.                 dfprty = 'm';        /* Mark parity */
  283.             else
  284.                 dfprty = 's';        /* Space parity */
  285.         else                    /* Even or odd */
  286.             if (iob->io_SerFlags & SERF_PARTY_ODD)
  287.                 dfprty = 'o';        /* Odd parity */
  288.             else
  289.                 dfprty = 'e';        /* Even parity */
  290.     else
  291.         dfprty = 0;                /* No parity. */
  292.     ttprty = dfprty;
  293.  
  294.     CloseDevice((IOR *)iob);
  295.     serialopen = FALSE;
  296.     atexit(emergency);
  297.     return(0);
  298. }
  299.  
  300. /*
  301.  * syscleanup -- Amiga specific cleanup
  302.  */
  303. syscleanup(void)
  304. {
  305.     /* close everything */
  306.     if (serialopen) CloseDevice((IOR *)ReadIOB);
  307.     if (timeropen) CloseDevice((IOR *)TimerIOB);
  308.     if (TimerIOB) DeleteExtIO((IOR *)TimerIOB);
  309.     if (WriteIOB) DeleteExtIO((IOR *)WriteIOB);
  310.     if (ReadIOB) DeleteExtIO((IOR *)ReadIOB);
  311.     if (serport) DeletePort(serport);
  312.     if (conpkt) DeletePacket(conpkt);
  313.     if (conport) DeletePort(conport);
  314.     reqres();
  315.     if (IntuitionBase)
  316.     {
  317.         CloseLibrary((struct Library *)IntuitionBase);
  318.         IntuitionBase = NULL;
  319.     }
  320.  
  321.     /* reset standard I/O */
  322.     if (rawcon > 0)
  323.     {
  324.         /* restore Lattice AmigaDOS file handles */
  325.         DOSFH(0) = Input();
  326.         DOSFH(1) = Output();
  327.         DOSFH(2) = saverr;
  328.         Close(rawcon);
  329.     }
  330.     serialopen = timeropen = 0;
  331.     TimerIOB = WriteIOB = ReadIOB = serport = conpkt = conport = NULL;
  332.     IntuitionBase = NULL;
  333.     rawcon = 0;
  334.     return 1;
  335. }
  336.  
  337. /*
  338.  * reqoff -- turn requestors off
  339.  *    When AmigaDOS encounters an error that user intervention can fix
  340.  *    (like inserting the correct disk), it normally puts up a requestor.
  341.  *    The following code disables requestors, causing an error to be
  342.  *    returned instead.
  343.  */
  344. void
  345. reqoff(void)
  346. {
  347.     pushwindow = CurProc->pr_WindowPtr;
  348.     CurProc->pr_WindowPtr = (APTR)-1;
  349. }
  350. /*
  351.  * reqpop -- restore requesters to action at last reqoff
  352.  */
  353. void
  354. reqpop(void)
  355. {
  356.     CurProc->pr_WindowPtr = pushwindow;
  357. }
  358.  
  359. /*
  360.  * reqres -- restore requestors to startup action
  361.  */
  362. void
  363. reqres(void)
  364. {
  365.     CurProc->pr_WindowPtr = savewindow;
  366. }
  367.  
  368. /*
  369.  * KillIO -- terminate an I/O request
  370.  */
  371. static int
  372. KillIO(struct IORequest *iob)
  373. {
  374.     AbortIO(iob);
  375.     return((int)WaitIO(iob));
  376. }
  377.  
  378. /*
  379.  * ttopen -- open the serial device
  380.  *    If already open, returns 0 immediately.
  381.  *    Otherwise, the ttname is compare to SERIALNAME and used to
  382.  *    open the serial device, and, if the value of *lcl is < 0, it is
  383.  *    reset to 1 indicating local mode.  Returns -1 on error.
  384.  *    timo is the length of time to wait before flunking open;  we don't
  385.  *    need this feature on the Amiga.
  386.  */
  387. int
  388. ttopen(char * ttname, int *lcl, int modem, int timo)
  389. {
  390.     struct IOExtSer *iob = ReadIOB;
  391.     char *p;
  392.     ULONG unit;
  393. static  char cttname[50];        /* Current open ttname */
  394.  
  395.     if (modem < 0) return -1;    /* We don't do networks yet. */
  396.     if (serialopen)            /* Already have serial device open */
  397.             if (strcmp(ttname, cttname) == 0)
  398.                 return(0);        /* Same device - ignore  */
  399.             else ttclos(0);        /* Different device - close */
  400.  
  401.     /* verify the serial name */
  402. #if 0
  403.     if (strcmp(ttname, SERIALNAME) != 0) return(-1);
  404. #endif
  405.  
  406.     /* set open modes.  We no longer open in shared mode. */
  407.     iob->io_SerFlags = (modem > 0 ? SERF_7WIRE : 0);
  408.  
  409.     /* parse device name as device/unit */
  410.     if ((p = strchr(ttname, '/')) == NULL)
  411.         unit = 0;
  412.     else {
  413.         if (*(p + strlen(p) - 1) == 's')    /* Open in shared mode */
  414.             {
  415.                 iob->io_SerFlags |= SERF_SHARED;
  416.                 *(p + strlen(p) - 1) = '\0';
  417.             }
  418.         unit = (ULONG) atoi(p + 1);
  419.         *p = '\0';
  420.     }
  421.     /* open the serial device */
  422.     if (OpenDevice(ttname, unit, (IOR *)iob, 0L) != 0)
  423.         return(-1);
  424.     serialopen = TRUE;
  425.     tvtflg = 0;
  426.     pendread = pendwrite = pendconsole = FALSE;
  427.     queuedser = -1;
  428.  
  429.     /* fill in the fields of the other IO blocks */
  430.     *WriteIOB = *iob;
  431.  
  432.     /* set local mode */
  433.     if (*lcl == -1)    *lcl = 1; /* always local */
  434.     if (p) *p = '/';        /* restore slash */
  435.         if (iob->io_SerFlags & SERF_SHARED)
  436.             *(p + strlen(p)) = 's';     /* restore suffix if present */
  437.     strcpy(cttname, ttname);
  438.     return(0);
  439. }
  440.  
  441. /*
  442.  * StartTimer -- start a timeout
  443.  */
  444. static VOID
  445. StartTimer(LONG secs, LONG micro)
  446. {
  447.     TimerIOB->tr_node.io_Command = TR_ADDREQUEST;
  448.     TimerIOB->tr_time.tv_secs  = secs;
  449.     TimerIOB->tr_time.tv_micro = micro;
  450.     SendIO((IOR *)TimerIOB);
  451. }
  452.  
  453. /*
  454.  * SerialWait -- wait for serial I/O to terminate
  455.  *    return I/O error
  456.  */
  457. static int
  458. SerialWait(struct IOExtSer *iob, int timeout)
  459. {
  460.     LONG sigs;
  461.     struct timerequest *timer = TimerIOB;
  462.     LONG waitsigs;
  463.  
  464.     /* set up timeout if necessary */
  465.     if (timeout > 0) StartTimer((LONG)timeout, 0L);
  466.  
  467.     /* wait for completion, timeout, or interrupt */
  468.     sigs = 0;
  469.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  470.     for (;;)
  471.     {
  472.         if (sigs & intsigs)
  473.         {    /* interrupted */
  474.             if (timeout > 0) KillIO((IOR *)timer);
  475.             KillIO((IOR *)iob);
  476.             testint(sigs);
  477.             return(-1);
  478.         }
  479.         if (CheckIO((IOR *)iob))
  480.         {
  481.             if (timeout > 0) KillIO((IOR *)timer);
  482.             return((int)WaitIO((IOR *)iob));
  483.         }
  484.         if (timeout > 0 && CheckIO((IOR *)timer))
  485.         {
  486.             KillIO((IOR *)iob);
  487.             WaitIO((IOR *)timer);
  488.             /* restart if XOFF'ed */
  489.             iob->IOSer.io_Command = CMD_START;
  490.             DoIO((IOR *)iob);
  491.             return(-1);
  492.         }
  493.         sigs = Wait(waitsigs);
  494.     }
  495. }
  496.  
  497. /*
  498.  * TerminateRead -- wait for queued read to finish
  499.  */
  500. static int
  501. TerminateRead(void)
  502. {
  503.     if (!pendread) return(0);
  504.     if (WaitIO((IOR *)ReadIOB) == 0) queuedser = serbufc;
  505.     pendread = FALSE;
  506.     return((int)ReadIOB->IOSer.io_Error);
  507. }
  508.  
  509. /*
  510.  * TerminateWrite -- ensure WriteIOB is ready for reuse
  511.  */
  512. static int
  513. TerminateWrite(int timeout)
  514. {
  515.     Chk_Abort();
  516.     if (!pendwrite) return(0);
  517.     pendwrite = FALSE;
  518.     if (timeout) {
  519.         timeout = WriteIOB->IOSer.io_Length * 80 / WriteIOB->io_Baud;
  520.     }
  521.     return(SerialWait(WriteIOB, timeout));
  522. }
  523.  
  524. /*
  525.  * SerialReset -- terminate pending serial and console I/O
  526.  */
  527. static void
  528. SerialReset(void)
  529. {
  530.     if (pendread)
  531.     {
  532.         AbortIO((IOR *)ReadIOB); /* should work even if read finished */
  533.         TerminateRead();
  534.     }
  535.  
  536.     if (pendconsole)
  537.     {    /* this does not happen normally */
  538.         WaitPort(conport);
  539.         GetMsg(conport);
  540.         pendconsole = FALSE;
  541.     }
  542.  
  543.     if (pendwrite)
  544.         TerminateWrite(1);
  545. }
  546.  
  547. /*
  548.  * ttres -- reset serial device
  549.  */
  550. ttres()
  551. {
  552.     if (!serialopen) return(-1);
  553.  
  554.     /* reset everything */
  555.     SerialReset();
  556.     ReadIOB->IOSer.io_Command = CMD_RESET;
  557.     tvtflg = 0;
  558.     return(DoIO((IOR *)ReadIOB) ? -1 : 0);
  559. }
  560.  
  561. /*
  562.  * ttclos -- close the serial device
  563.  */
  564. int
  565. ttclos(int foo)
  566. {
  567.     if (!serialopen) return(0);
  568.     if (ttres() < 0) return(-1);
  569.     CloseDevice((IOR *)ReadIOB);
  570.     serialopen = FALSE;
  571.     tvtflg = 0;
  572.     return(0);
  573. }
  574.  
  575. /*
  576.  * tthang -- hang up phone line
  577.  *    Drops DTR by closing serial.device
  578.  */
  579. int
  580. tthang(void)
  581. {
  582.         return((serialopen) ? ttclos(0) : -1);
  583. }
  584.  
  585. /*
  586.  * ttpkt -- set serial device up for packet transmission
  587.  *    sets serial parameters
  588.  */
  589. int
  590. ttpkt(long speed, int flow, int parity)
  591. {
  592.     extern UBYTE eol;
  593.     struct IOExtSer *iob = ReadIOB;
  594.  
  595.     if (!serialopen || pendread) return(-1);
  596.  
  597.     /* terminate any pending writes */
  598.     TerminateWrite(1);
  599.  
  600.     /* fill in parameters */
  601.     iob->io_CtlChar = 0x11130000;
  602.     if (speed >= 0 && ttsspd((int) (speed / 10)) >= 0) iob->io_Baud = speed;
  603.     iob->io_RBufLen = speed;    /* 10 seconds worth of data */
  604.     /*
  605.      * Notice the dopar(eol) here to set the EOL character with the
  606.      * appropriate parity.  See also ttinl().
  607.      */
  608.     memset(&iob->io_TermArray, dopar(eol), sizeof(struct IOTArray));
  609.     iob->io_ReadLen = iob->io_WriteLen = 8;
  610.     iob->io_StopBits = 1;
  611.     if (flow == FLO_XONX)
  612.         iob->io_SerFlags &= ~(SERF_XDISABLED | SERF_7WIRE);
  613.     else if (flow == FLO_NONE) {
  614.         iob->io_SerFlags |= SERF_XDISABLED;
  615.         iob->io_SerFlags &= ~SERF_7WIRE;
  616.     } else if (flow == FLO_RTSC)
  617.         iob->io_SerFlags |= (SERF_XDISABLED | SERF_7WIRE);
  618.     else {
  619.         puts("Only XON/XOFF and RTS/CTS are available");
  620.         iob->io_SerFlags |= SERF_XDISABLED;
  621.         iob->io_SerFlags &= ~SERF_7WIRE;
  622.     }
  623.     /* if no XON/XOFF flow and high baud rate, RAD_BOOGIE is appropriate */
  624.     if (flow != FLO_XONX && iob->io_Baud >= 19200)
  625.         iob->io_SerFlags |= SERF_RAD_BOOGIE;
  626.     else
  627.         iob->io_SerFlags &= ~SERF_RAD_BOOGIE;
  628.  
  629.     /*
  630.      * Parity setting.  For packet send/receive, we turn off the
  631.      * Amiga's internal parity generation and checking, as this code
  632.      * does it itself (which makes it bigger and slower...).  We
  633.      * save the current parity for ttinl().
  634.      */
  635.  
  636.     ttprty = parity;
  637.     iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD);
  638.     iob->io_ExtFlags = 0;        /* MUST BE ZERO unless Mark or Space. */
  639.  
  640.     /* set the parameters */
  641.     iob->IOSer.io_Command = SDCMD_SETPARAMS;
  642.     if (DoIO((IOR *)iob) != 0) return(-1);
  643.     tvtflg = 0;
  644.     return(ttflui());
  645. }
  646.  
  647. /*
  648.  * ttvt -- set up serial device for connect mode.  This is almost the same
  649.  * as ttpkt() on the Amiga, except we save the settings and a flag and return
  650.  * without doing anything if we've already been called with the same
  651.  * values.
  652.  */
  653. int
  654. ttvt(long speed, int flow) {
  655.     static long ospeed = -1;
  656.     static int oflow = -9;
  657.  
  658.     if (tvtflg != 0 && ospeed == speed && oflow == flow)
  659.         return 0;
  660.     if (ttpkt(speed, flow, 0) < 0)
  661.         return -1;
  662.     ospeed = speed;            /* Save speed */
  663.     oflow = flow;            /* and flow control set */
  664.     tvtflg = 1;            /* and flag we've been called */
  665.     return 0;
  666. }
  667.  
  668. /*  T T S S P D  --  Checks and sets transmission rate.  */
  669.  
  670. /*  Call with speed in characters (not bits!) per second. */
  671. /*  Returns 0 if successful, -1 otherwise. */
  672.  
  673. int
  674. ttsspd(int cps) {
  675. #ifdef    NETCONN
  676.     if (netconn) return (0);
  677. #endif    /* NETCONN */
  678.  
  679.     if (cps <= 0) return(-1);
  680.  
  681.     /* First check that the given speed is valid. */
  682.     /* 888 means 75/1200 split speed */
  683.     if (cps == 888 || cps < 11) {
  684.     return -1;
  685.     }
  686.  
  687.     return cps;
  688. }
  689.  
  690. /* T T G S P D  -  Get speed of currently selected tty line  */
  691.  
  692. /*
  693.   Read speed from serial.device, or, if not open, return the value in
  694.   the current ReadIOB.
  695. */
  696. long
  697. ttgspd(void) {                /* Get current tty speed */
  698.     struct IOExtSer *myread = ReadIOB;
  699.  
  700.     if (!serialopen)
  701.         if (myread != NULL) return((long)myread->io_Baud);
  702.         else return -1;
  703.     Chk_Abort();
  704.     if (pendread && !CheckIO((IOR *)myread)) return(0);
  705.     if (TerminateRead() != 0) return(-1);
  706.     myread->IOSer.io_Command = SDCMD_QUERY;
  707.     return((DoIO((IOR *)myread) == 0)
  708.             ? (long)myread->io_Baud
  709.             : -1);
  710. }
  711.  
  712. /*
  713.  * ttflui -- flush serial device input buffer
  714.  */
  715. int
  716. ttflui(void)
  717. {
  718.     if (!serialopen || pendread) return(-1);
  719.     queuedser = -1;
  720.     ReadIOB->IOSer.io_Command = CMD_CLEAR;
  721.     return(DoIO((IOR *)ReadIOB) ? -1 : 0);
  722. }
  723.  
  724. /*
  725.  * ttfluo -- flush serial output buffer
  726.  */
  727. int
  728. ttfluo(void)
  729. {
  730.     if (!serialopen || pendwrite) return -1;
  731.     WriteIOB->IOSer.io_Command = CMD_CLEAR;
  732.     return(DoIO((IOR *)WriteIOB) ? -1 : 0);
  733. }
  734.  
  735.  
  736. /*
  737.  * test for and catch interrupt
  738.  */
  739. static void
  740. testint(LONG sigs)
  741. {
  742.     /* test for and reset caught interrupt signals */
  743.     if ((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) {
  744.         raise(SIGINT);
  745.     }
  746. }
  747.  
  748. /*
  749.  * conint -- set console interrupt handler and suspend handler.
  750.  */
  751. void
  752. conint(SIGTYP (*newhdlr)(int), SIGTYP (*stophdlr)(int))
  753. {
  754.     Chk_Abort();            /* handle any pending interrupts */
  755.     signal(SIGINT, newhdlr);    /* set the new handler */
  756.     intsigs = BREAKSIGS;        /* note signal caught */
  757. }
  758.  
  759. /*
  760.  * connoi -- disable interrupt trapping
  761.  */
  762. void
  763. connoi(void)
  764. {
  765.     signal(SIGINT, SIG_IGN);    /* disable interrupts */
  766.     intsigs = 0;            /* note signal ignored */
  767.     Chk_Abort();            /* ignore pending interrupts */
  768. }
  769.  
  770. /*
  771.  * ttchk -- return number of chars immediately available from serial device
  772.  */
  773. int
  774. ttchk(void)
  775. {
  776.     struct IOExtSer *myread = ReadIOB;
  777.  
  778.     if (!serialopen) return(-1);
  779.     Chk_Abort();
  780.     if (pendread && !CheckIO((IOR *)myread)) return(0);
  781.     if (TerminateRead() != 0) return(-1);
  782.     myread->IOSer.io_Command = SDCMD_QUERY;
  783.     return((DoIO((IOR *)myread) == 0)
  784.             ? ((queuedser >= 0 ? 1 : 0) + (int)myread->IOSer.io_Actual)
  785.             : -1);
  786. }
  787.  
  788. /*
  789.  * ttxin -- get n characters from serial device.  This routine should
  790.  * only be called when we know that there are at least n characters
  791.  * ready to be read.
  792.  */
  793. int
  794. ttxin(int n, CHAR *buf)
  795. {
  796.         return(ttinl(buf, n, 0, 0));
  797. }
  798.  
  799. #ifdef PARSENSE
  800.  
  801. extern CHAR partab[];
  802.  
  803. /*  P A R C H K  --  Check if Kermit packet has parity  */
  804.  
  805. /*
  806.   Call with s = pointer to packet, start = packet start character, n = length.
  807.   Returns 0 if packet has no parity, -1 on error, or if packet has parity:
  808.     'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
  809. */
  810. parchk(s,start,n) CHAR *s, start; int n; {
  811.     CHAR s0, s1, s2, s3, sn;
  812.  
  813.     debug(F101,"parchk n","",n);
  814.     debug(F101,"parchk start","",start);
  815.     debug(F110,"parchk s",s,0);
  816.  
  817.     s0 = s[0] & 0x7f;            /* Mark field (usually Ctrl-A) */
  818.  
  819.     if (s0 != start || n < 5) return(-1); /* Not a valid packet */
  820.  
  821. /* Look at packet control fields, which never have 8th bit set */
  822. /* First check for no parity, most common case. */
  823.  
  824.     if (((s[0] | s[1] | s[2] | s[3] | s[n-2]) & 0x80) == 0)
  825.       return(0);            /* No parity */
  826.  
  827. /* Check for mark parity */
  828.  
  829.     if (((s[0] & s[1] & s[2] & s[3] & s[n-2]) & 0x80) == 0x80)
  830.       return('m');            /* Mark parity */
  831.  
  832. /* Packet has some kind of parity */
  833. /* Make 7-bit copies of control fields */
  834.  
  835.     s1 = s[1] & 0x7f;            /* LEN */
  836.     s2 = s[2] & 0x7f;            /* SEQ */
  837.     s3 = s[3] & 0x7f;            /* TYPE */
  838.     sn = s[n-2] & 0x7f;            /* CHECK */
  839.  
  840. /* Check for even parity */
  841.  
  842.     if ((s[0] == partab[s0]) &&
  843.         (s[1] == partab[s1]) &&
  844.         (s[2] == partab[s2]) &&
  845.     (s[3] == partab[s3]) &&
  846.     (s[n-2] == partab[sn]))
  847.       return('e');
  848.  
  849. /* Check for odd parity */
  850.  
  851.     if ((s[0] != partab[s0]) &&
  852.         (s[1] != partab[s1]) &&
  853.         (s[2] != partab[s2]) &&
  854.     (s[3] != partab[s3]) &&
  855.     (s[n-2] != partab[sn]))
  856.       return('o');
  857.  
  858. /* Otherwise it's probably line noise.  Let checksum calculation catch it. */
  859.  
  860.     return(-1);
  861. }
  862. #endif /* PARSENSE */
  863.  
  864. /*
  865.  * ttinc -- read character from serial line
  866.  */
  867. int
  868. ttinc(int timeout)
  869. {
  870.     UBYTE ch;
  871.  
  872.     return((ttinl((CHAR *)&ch, 1, timeout, 0) > 0) ? (int)ch : -1);
  873. }
  874.  
  875. /*
  876.  * ttol -- write n chars to serial device.  For small writes, we have
  877.  * a small local buffer which allows them to run asynchronously.  For
  878.  * large writes, we do them synchronously.  This seems to be the best
  879.  * compromise between speed and code simplicity and size.
  880.  *
  881.  * Stephen Walton, 23 October 1989
  882.  */
  883. int
  884. ttol(CHAR *buf, int n)
  885. {
  886.     struct IOExtSer *mywrite = WriteIOB;
  887.     static char outbuf[1024];    /* safe place for output characters */
  888.     int s;
  889.     int oldn = n;
  890.  
  891.     if (!serialopen) return(-1);
  892.     if ((s = n - sizeof(outbuf)) > 0) {
  893.         if (TerminateWrite(1) != 0) return(-1);
  894.         mywrite->IOSer.io_Command = CMD_WRITE;
  895.         mywrite->IOSer.io_Data  = (APTR) buf;
  896.         mywrite->IOSer.io_Length = s;
  897.         SendIO((IOR *)mywrite);
  898.         pendwrite = TRUE;
  899.         buf += s;
  900.         n   -= s;
  901.         memcpy(outbuf, buf, n);
  902.         if (TerminateWrite(1) != 0) return(-1);
  903.     } else {
  904.         if (TerminateWrite(1) != 0) return(-1);
  905.         memcpy(outbuf, buf, n);
  906.     }
  907.     mywrite->IOSer.io_Command = CMD_WRITE;
  908.     mywrite->IOSer.io_Data    = (APTR)outbuf;
  909.     mywrite->IOSer.io_Length  = n;
  910.     SendIO((IOR *)mywrite);
  911.     pendwrite = TRUE;
  912.  
  913.     return oldn;
  914. }
  915.  
  916. /*
  917.  * ttoc -- output single character to serial device
  918.  */
  919. int
  920. ttoc(char c)
  921. {
  922.         return(ttol((CHAR *) &c, 1));
  923. }
  924.  
  925. /*
  926.  * ttinl -- read from serial device, possibly with timeout and eol character
  927.  *    reads up to n characters, returning the number of characters read
  928.  *    if eol > 0, reading the eol character will terminate read
  929.  *    if timeout > 0, terminates read if timeout elapses
  930.  *    returns -1 on error, such as timeout or interrupt
  931.  *
  932.  *    Note that this is the single routine which does all character reading
  933.  *    in Amiga C Kermit, and has some added "features" compared to, say,
  934.  *    the Unix version.  If timeout is 0, this routine waits forever.
  935.  *    If eol is zero, it is not used.
  936.  *
  937.  *    New for 5A(157) is the start parameter, which is the start-of-packet
  938.  *    character.  Following the Unix example, we just read until eol,
  939.  *    but return a bad packet if the first character we got doesn't agree
  940.  *    with start.
  941.  */
  942. int
  943. ttinl(CHAR *buf, int n, int timeout, CHAR eol)
  944. {
  945.         unsigned  mask;
  946.     struct IOExtSer *myread = ReadIOB;
  947.     int count;
  948.     int nread, i;
  949.  
  950.     Chk_Abort();
  951.      if (!serialopen || pendread || n <= 0) return(-1);
  952.  
  953.     mask = (ttprty ? 0177 : 0377);    /* parity stripping mask */
  954.  
  955.     /* handle pushback */
  956.     if (queuedser >= 0)
  957.     {
  958.         *buf = queuedser & mask;    /* Strip queued character. */
  959.         queuedser = -1;
  960.         if (*buf == eol || n == 1) return(1);
  961.         ++buf;
  962.         --n;
  963.         count = 1;
  964.     }
  965.     else
  966.         count = 0;
  967.  
  968.     /* set up line terminator */
  969.     if (eol > 0)
  970.     {
  971.         /*
  972.          * For reasons which are obscure to me, this batch of
  973.          * code generally fails.  Normally, this doesn't matter,
  974.          * because io_TermArray is set in ttpkt() above, and so
  975.          * this code is only executed if eol changes as a result
  976.          * of the initial packet negotiation.  I found the bug
  977.          * by inadvertently not using dopar(eol) in the setting
  978.          * of io_TermArray in ttpkt(), which did cause this code
  979.          * to be called if parity was MARK or EVEN (since in that
  980.          * case dopar(eol) != eol).
  981.          */
  982.  
  983.         if (dopar(eol) != *(UBYTE *)&myread->io_TermArray)
  984.         {
  985.             memset(&myread->io_TermArray, dopar(eol),
  986.                    sizeof(struct IOTArray));
  987.             myread->IOSer.io_Command = SDCMD_SETPARAMS;
  988.             if (DoIO((IOR *)myread) != 0) {
  989.                 debug(F111, "SETPARAMS fails in ttinl()",
  990.                       "io_Error", (int) myread->IOSer.io_Error);
  991.                 myread->io_TermArray.TermArray0 =
  992.                     myread->io_TermArray.TermArray1 = 0xffffffffu;
  993.                 return -1;
  994.             }
  995.         }
  996.         myread->io_SerFlags |= SERF_EOFMODE;
  997.     }
  998.     else
  999.         myread->io_SerFlags &= ~SERF_EOFMODE;
  1000.  
  1001.     /* set up the read */
  1002.     myread->IOSer.io_Command = CMD_READ;
  1003.     myread->IOSer.io_Data    = (APTR)buf;
  1004.     myread->IOSer.io_Length  = n;
  1005.  
  1006.     /* perform read quickly if possible */
  1007.     myread->IOSer.io_Flags = IOF_QUICK;
  1008.     BeginIO((IOR *)myread);
  1009.     if (myread->IOSer.io_Flags & IOF_QUICK)
  1010.         myread->IOSer.io_Flags = 0;
  1011.     else
  1012.         /* wait for read to complete if no QUICK. */
  1013.         if (SerialWait(myread, timeout) != 0)
  1014.             return -1;
  1015.  
  1016.     if (myread->IOSer.io_Error != 0)
  1017.         return -1;
  1018. #if COMMENT
  1019.     if (start != 0 && (buf[0] & mask) != start) /* Bad packet */
  1020.         return -1;
  1021. #endif
  1022.     /* Strip parity bits if need be. */
  1023.     nread = (int) myread->IOSer.io_Actual;
  1024.     if (ttprty)
  1025.         for (i = 0; i < nread; i++)
  1026.             buf[i] &= mask;
  1027.     if (nread > 1)
  1028.         buf[nread] = '\0';        /* Null terminate */
  1029.     return(count + nread);
  1030. }
  1031.  
  1032. /*
  1033.  * Sleeper -- perform an interruptible timeout
  1034.  */
  1035. static int
  1036. Sleeper(LONG secs, LONG micro)
  1037. {
  1038.     LONG sigs;
  1039.     LONG waitsigs;
  1040.     struct timerequest *timer = TimerIOB;
  1041.  
  1042.     if (!timeropen) return(-1);
  1043.     StartTimer(secs, micro);
  1044.     sigs = 0;
  1045.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  1046.     for (;;)
  1047.     {
  1048.         if (CheckIO((IOR *)timer))
  1049.         {
  1050.             WaitIO((IOR *)timer);
  1051.             return(0);
  1052.         }
  1053.         if (sigs & intsigs)
  1054.         {
  1055.             KillIO((IOR *)timer);
  1056.             testint(sigs);
  1057.             return(-1);
  1058.         }
  1059.         sigs = Wait(waitsigs);
  1060.     }
  1061. }
  1062.  
  1063. /*
  1064.  * sleep -- wait n seconds
  1065.  */
  1066. int
  1067. sleep(int n)
  1068. {    return(Sleeper((LONG)n, 0L)); }
  1069.  
  1070. /*
  1071.  * msleep -- wait n milliseconds
  1072.  */
  1073. int
  1074. msleep(int m)
  1075. {    return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); }
  1076.  
  1077.  
  1078. /*
  1079.  * rtimer -- reset elapsed time
  1080.  */
  1081. void
  1082. rtimer(void)
  1083. {    DateStamp(&prevtime); }
  1084.  
  1085. /*
  1086.  * gtimer -- get currently elapsed time in seconds
  1087.  */
  1088. int
  1089. gtimer(void)
  1090. {
  1091.     int x;
  1092.     struct DateStamp curtime;
  1093.  
  1094.     DateStamp(&curtime);
  1095.     x = ((curtime.ds_Days   - prevtime.ds_Days  ) * 1440 +
  1096.          (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 +
  1097.          (curtime.ds_Tick   - prevtime.ds_Tick  ) / 50;
  1098.     return((x < 0) ? 0 : x );
  1099. }
  1100.  
  1101. /*
  1102.  * ztime -- format current date and time into string
  1103.  */
  1104. void
  1105. ztime(char **s)
  1106. {
  1107.    /*
  1108.     * The following date code taken from a USENET article by
  1109.     *    Tomas Rokicki(rokicki@Navajo.ARPA)
  1110.     */
  1111.    static char *months[] = { NULL,
  1112.       "January","February","March","April","May","June",
  1113.       "July","August","September","October","November","December"};
  1114.    static char buf[32];
  1115.  
  1116.    long n ;
  1117.    int m, d, y ;
  1118.    struct DateStamp datetime;
  1119.  
  1120.    DateStamp(&datetime);
  1121.  
  1122.    n = datetime.ds_Days - 2251 ;
  1123.    y = (4 * n + 3) / 1461 ;
  1124.    n -= 1461 * y / 4 ;
  1125.    y += 1984 ;
  1126.    m = (5 * n + 2) / 153 ;
  1127.    d = n - (153 * m + 2) / 5 + 1 ;
  1128.    m += 3 ;
  1129.    if (m > 12) {
  1130.       y++ ;
  1131.       m -= 12 ;
  1132.    }
  1133.    sprintf(buf, "%02d:%02d:%02d %s %d, %d",
  1134.            datetime.ds_Minute / 60, datetime.ds_Minute % 60,
  1135.        datetime.ds_Tick / 50, months[m], d, y) ;
  1136.    *s = buf;
  1137. }
  1138.  
  1139. /*
  1140.  * congm -- save console modes
  1141.  */
  1142. int
  1143. congm(void)
  1144. {
  1145.     if (!saverr) saverr = DOSFH(2);
  1146.     return(0);
  1147. }
  1148.  
  1149. /*
  1150.  * CreateWindow -- create window and jam it into standard I/O
  1151.  */
  1152. int
  1153. CreateWindow(int esc)
  1154. {
  1155.     char rawname[48];
  1156.     struct Screen s;
  1157.  
  1158.     if (rawcon > 0) return(0);
  1159.     congm();
  1160.  
  1161.     if (GetScreenData(&s, sizeof(s), WBENCHSCREEN, NULL) == 0) {
  1162.         s.Width = 640;
  1163.         s.Height = 200;
  1164.     }
  1165.     sprintf(rawname, "RAW:0/1/%d/%d/Kermit%s", s.Width, s.Height - 1,
  1166.         v37? "/ALT0/1/100/30" : "");
  1167.     rawcon = Open(rawname, (LONG)MODE_NEWFILE);
  1168.       if (rawcon == 0)
  1169.           return(-1);
  1170.     DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon;
  1171.  
  1172.     /* if we create a window, don't abort on errors or echo */
  1173.     backgrd = FALSE;
  1174.     ckxech = 1;
  1175.     return(0);
  1176. }
  1177.  
  1178. /*
  1179.  * concb -- put console in single character wakeup mode
  1180.  */
  1181. int
  1182. concb(char esc)
  1183. {
  1184.     if (rawcon) return(0);
  1185.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  1186.         return(0);
  1187.     return(CreateWindow(esc));
  1188. }
  1189.  
  1190. /*
  1191.  * conbin -- put console in raw mode
  1192.  */
  1193. int
  1194. conbin(char esc)
  1195. {
  1196.     if (rawcon) return(0);
  1197.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  1198.         return(isatty(0) ? 0 : -1);
  1199.     return(CreateWindow(esc));
  1200. }
  1201.  
  1202. /*
  1203.  * conres -- restore console
  1204.  *    we actually restore in syscleanup()
  1205.  */
  1206. conres()
  1207. {
  1208.         return(0);
  1209. }
  1210.  
  1211. /*
  1212.  * conoc -- output character to console
  1213.  */
  1214. int
  1215. conoc(char c)
  1216. {
  1217.     putchar(c);
  1218.     fflush(stdout);
  1219.     Chk_Abort();
  1220.     return c;
  1221. }
  1222.  
  1223. /*
  1224.  * conxo -- output x chars to console
  1225.  */
  1226. int
  1227. conxo(int n, char *buf)
  1228. {
  1229.     int retval;
  1230.  
  1231.     fflush(stdout);
  1232.     retval = write(FILENO(1), buf, n);
  1233.     Chk_Abort();
  1234.     return retval;
  1235. }
  1236.  
  1237. /*
  1238.  * conol -- output line to console
  1239.  */
  1240. int
  1241. conol(char *l)
  1242. {
  1243.     int retval;
  1244.     retval = fputs(l, stdout);
  1245.     fflush(stdout);
  1246.     Chk_Abort();
  1247.     return retval;
  1248. }
  1249.  
  1250. /*
  1251.  * conola -- output line array to console
  1252.  */
  1253. int
  1254. conola(char **l)
  1255. {
  1256.     for (; **l; ++l)
  1257.         if (conol(*l) < 0)
  1258.             return(-1);
  1259.     return 0;
  1260. }
  1261.  
  1262. /*
  1263.  * conoll -- output line with CRLF
  1264.  */
  1265. int
  1266. conoll(char *l)
  1267. {
  1268.     if (conol(l) < 0)
  1269.         return -1;
  1270.     if (conxo(2, "\r\n") < 0)
  1271.         return -1;
  1272.     return 0;
  1273. }
  1274.  
  1275. /*
  1276.  * conchk -- returns nonzero if characters available from console
  1277.  */
  1278. int
  1279. conchk(void)
  1280. {
  1281.     fflush(stdout);
  1282.     Chk_Abort();
  1283.     return(WaitForChar(DOSFH(0), 0L) != 0);
  1284. }
  1285.  
  1286. /*
  1287.  * coninc -- get input character from console
  1288.  */
  1289. int
  1290. coninc(int timeout)
  1291. {
  1292.     UBYTE ch;
  1293.  
  1294.     fflush(stdout);
  1295.     Chk_Abort();
  1296.     if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L))
  1297.         return(-1);
  1298.     if (read(FILENO(0), &ch, 1) < 1) return(-1);
  1299.     Chk_Abort();
  1300.     return((int)ch);
  1301. }
  1302.  
  1303. /*
  1304.  * T T S C A R R -- Copy desired character mode to global ttcarr for future
  1305.  * and later use.
  1306.  */
  1307. ttscarr(carrier) int carrier; {
  1308.     ttcarr = carrier;
  1309.     debug(F101, "ttscarr","",ttcarr);
  1310.     return(ttcarr);
  1311. }
  1312.  
  1313. static int
  1314. sendbreak(long time) {
  1315.     if (!serialopen) return(-1);
  1316.     /* flush queued output */
  1317.     TerminateWrite(1);
  1318.     nttoq = 0;
  1319.     pendwrite = TRUE;
  1320.     WriteIOB->IOSer.io_Command = SDCMD_SETPARAMS;
  1321.     WriteIOB->io_BrkTime = time;
  1322.     (void) DoIO((IOR *)WriteIOB);
  1323.     pendwrite = TRUE;
  1324.     WriteIOB->IOSer.io_Command = SDCMD_BREAK;
  1325.     WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK;
  1326.     SendIO((IOR *)WriteIOB);
  1327.     return(0);
  1328. }
  1329.  
  1330. /*
  1331.  * ttsndb -- send a BREAK
  1332.  *    flushes queued and active output
  1333.  */
  1334. int
  1335. ttsndb(void)
  1336. {
  1337.     return(sendbreak(275000L));
  1338. }
  1339.  
  1340. /*
  1341.  * ttsndlb -- send a long BREAK (1.5 sec)
  1342.  */
  1343. int
  1344. ttsndlb(void) {
  1345.     return(sendbreak(1500000L));
  1346. }
  1347.  
  1348. /*  T T W M D M  --  Wait for modem signals  */
  1349.  
  1350. /*
  1351.   Wait up to timo seconds for all of the given modem signals to appear.
  1352.   mdmsig is a bit mask, in which:
  1353.    BM_CTS (bit 0) means wait for Clear To Send
  1354.    BM_DSR (bit 1) means wait for Data Set Ready
  1355.    BM_DCD (bit 2) means wait for Carrier Detect
  1356.   Returns:
  1357.   -3 Not implemented.
  1358.   -2 This line does not have modem control.
  1359.   -1 Timeout: time limit exceeded before all signals were detected.
  1360.    1 Success.
  1361. */
  1362. int
  1363. ttwmdm(int mdmsig, int timo) {
  1364.     return(-3);
  1365. }
  1366.  
  1367. /*  T T G M D M  --  Get modem signals  */
  1368. /*
  1369.  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  1370.  on in as its return value, in a bit mask as described for ttwmdm.  Returns:
  1371.  -3 Not implemented
  1372.  -2 if the line does not have modem control
  1373.  -1 on error.
  1374.  >= 0 on success, with a bit mask containing the modem signals that are on.
  1375. */
  1376.  
  1377. int
  1378. ttgmdm(void) {
  1379.     return(-3);
  1380. }
  1381.  
  1382.  
  1383. /*
  1384.  * ttocq -- write char to serial device, queueing if necessary
  1385.  *    returns -2 on overrun, -1 on serial error
  1386.  *    use only in connect mode
  1387.  */
  1388. int
  1389. ttocq(char c)
  1390. {
  1391.     int i;
  1392.  
  1393.     if (!serialopen) return(-1);
  1394.     if (pendwrite && CheckIO((IOR *)WriteIOB))
  1395.     {
  1396.         pendwrite = FALSE;
  1397.         if (WaitIO((IOR *)WriteIOB) != 0) return(-1);
  1398.     }
  1399.     if (pendwrite)
  1400.     {
  1401.         if (nttoq >= NTTOQ) return(-2);        /* overrun */
  1402.         ttoq[(pttoq + nttoq++) % NTTOQ] = c;
  1403.     }
  1404.     else if (nttoq == 0)
  1405.         return(ttoc(c));
  1406.     else
  1407.     {
  1408.         i = ttoc(ttoq[pttoq]);
  1409.         ttoq[(pttoq + nttoq) % NTTOQ] = c;
  1410.         pttoq = (pttoq + 1) % NTTOQ;
  1411.         if (i < 0) return(-1);
  1412.     }
  1413.     return(1);
  1414. }
  1415.  
  1416. /*
  1417.  * ttonq -- returns number of characters in serial output queue
  1418.  */
  1419. int
  1420. ttonq(void)
  1421. {
  1422.         return(nttoq);
  1423. }
  1424.  
  1425. /*
  1426.  * conttb -- prepare for contti() usage
  1427.  */
  1428. void
  1429. conttb(void)
  1430. {
  1431.     /* flush queued input and output */
  1432.     queuedcon = -1;
  1433.     pttoq = nttoq = 0;
  1434. }
  1435.  
  1436. /*
  1437.  * contte -- end contti() usage
  1438.  *    this can be called after a tthang, it which case ttres will already
  1439.  *    have done this cleanup
  1440.  */
  1441. void
  1442. contte(void)
  1443. {
  1444.     /* clear any pending ^C, ^D interrupts */
  1445.     Chk_Abort();
  1446.  
  1447.     /* terminate any pending I/O */
  1448.     if (serialopen) SerialReset();
  1449. }
  1450.  
  1451. /*
  1452.  * contti -- wait for console or tty input
  1453.  *    returns next console input or -1 when serial input available
  1454.  */
  1455. int
  1456. contti(void)
  1457. {
  1458.     int i;
  1459.     LONG waitsigs;
  1460.     struct DosPacket *pkt = conpkt;
  1461.     struct IOExtSer *myread = ReadIOB;
  1462.     static UBYTE conchar;
  1463.     BPTR dosfh = DOSFH(0);
  1464.     struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh);
  1465.  
  1466.     if (queuedcon >= 0)
  1467.     {
  1468.         conchar = queuedcon;
  1469.         queuedcon = -1;
  1470.         return((int)conchar);
  1471.     }
  1472.  
  1473.     if (!pendconsole)
  1474.     {    /* start a console read */
  1475.         pkt->dp_Port = conport;
  1476.         pkt->dp_Type = ACTION_READ;
  1477.         pkt->dp_Arg1 = (LONG)dosfh;
  1478.         pkt->dp_Arg2 = (LONG)&conchar;
  1479.         pkt->dp_Arg3 = 1;
  1480.         PutMsg(fh->fh_Process, pkt->dp_Link);
  1481.         pendconsole = TRUE;
  1482.     }
  1483.  
  1484.     if (queuedser < 0 && !pendread)
  1485.     {    /* start a serial read */
  1486.         myread->IOSer.io_Command = CMD_READ;
  1487.         myread->IOSer.io_Data    = (APTR)&serbufc;
  1488.         myread->IOSer.io_Length  = 1;
  1489.         SendIO((IOR *)myread);
  1490.         pendread = TRUE;
  1491.     }
  1492.  
  1493.     waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit);
  1494.     for (;;)
  1495.     {
  1496.         if (pendwrite && CheckIO((IOR *)WriteIOB))
  1497.         {
  1498.             WaitIO((IOR *)WriteIOB);
  1499.             pendwrite = FALSE;
  1500.             if (nttoq > 0)
  1501.             {
  1502.                 i = ttoc(ttoq[pttoq]);
  1503.                 pttoq = (pttoq + 1) % NTTOQ;
  1504.                 --nttoq;
  1505.                 if (i < 0) return(-1);
  1506.             }
  1507.         }
  1508.  
  1509.         /* give the console first chance */
  1510.         if (GetMsg(conport))
  1511.         {
  1512.             pendconsole = FALSE;
  1513.             if (pkt->dp_Res1 != 1) return(-1);
  1514.             /* translate CSI to ESC [ */
  1515.             if (conchar == 0x9B)
  1516.             {
  1517.                     conchar = 0x1B;
  1518.                 queuedcon = '[';
  1519.             }
  1520.             return((int)conchar);
  1521.         }
  1522.  
  1523.         if (queuedser >= 0) return(-2);
  1524.  
  1525.         if (CheckIO((IOR *)myread))
  1526.             return((TerminateRead() == 0) ? -2 : -1);
  1527.  
  1528.         Wait(waitsigs);
  1529.     }
  1530. }
  1531.  
  1532. /* P S U S P E N D -- Put current process in background. */
  1533.  
  1534. /*
  1535.  * Even though this isn't supported on the Amiga, I return success anyway.
  1536.  * After all, the user can pop the window to the back and do something
  1537.  * else any time he wants.
  1538.  */
  1539.  
  1540. int
  1541. psuspend(int foo) {
  1542.     return 0;
  1543. }
  1544.  
  1545. /* P R I V _ functions -- all dummy on the Amiga. */
  1546.  
  1547. int
  1548. priv_ini(void) {
  1549.     return 0;
  1550. }
  1551.  
  1552.  
  1553. int
  1554. priv_on(void) {
  1555.     return 0;
  1556. }
  1557.  
  1558. int
  1559. priv_off(void) {
  1560.     return 0;
  1561. }
  1562.  
  1563. int
  1564. priv_can(void) {
  1565.     return 0;
  1566. }
  1567.